package template

import (
	"database/sql"
	"errors"
)


type FNBeforeQuery func() error
type FNScanRow func(rows *sql.Rows) error

type tBaseDAO struct {
	fnBeforeQuery FNBeforeQuery
	fnScanRow FNScanRow
}

func newBaseDAO(fq FNBeforeQuery, fs FNScanRow) *tBaseDAO {
	return &tBaseDAO{
		fnBeforeQuery: fq,
		fnScanRow: fs,
	}
}

func (me *tBaseDAO) QueryOne(db *sql.DB, sql string, args... interface{}) error {
	if me.fnScanRow == nil {
		return errors.New("tBaseDAO.fnScanRow is nil")
	}

	if me.fnBeforeQuery != nil {
		e := me.fnBeforeQuery()
		if e != nil {
			return e
		}
	}

	rows, e := db.Query(sql, args...)
	defer func() {
		if rows != nil {
			_ = rows.Close()
		}
	}()

	if e != nil {
		return e
	}

	if rows.Next() {
		return me.fnScanRow(rows)
	} else {
		return errors.New("no rows found")
	}
}

func (me *tBaseDAO) QueryMulti(db *sql.DB, sql string, args... interface{}) error {
	if me.fnScanRow == nil {
		return errors.New("tBaseDAO.fnScanRow is nil")
	}

	if me.fnBeforeQuery != nil {
		e := me.fnBeforeQuery()
		if e != nil {
			return e
		}
	}

	rows, e := db.Query(sql, args...)
	defer func() {
		if rows != nil {
			_ = rows.Close()
		}
	}()

	if e != nil {
		return e
	}

	for rows.Next() {
		e = me.fnScanRow(rows)
		if e != nil {
			return e
		}
	}

	return nil
}